/*
 * Author: Tomer
 */
package org.tau.workshop2011.showcase

import java.io.InputStream;
import java.util.Properties;

import javax.mail.BodyPart;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
	

import scala.collection.mutable.ArrayBuffer

/* Should construct class with following parametrs:
 * user email(entire address)
 * user name
 * user password
 * 
 */


class ScalaEmail (emailString: String , user: String , pass: String) { 
  
  private val emailAddress : String = emailString; 
  private val username : String = user; 
  private val password : String = pass; 
  
  
   /*Fetches mail from "from" msgNum to "to" msgNum not including "to"
    * 
    */
   def batchFetch (fromMsgNum: Int, toMsgNum: Int) : ArrayBuffer[mailList] = {
    if((0>=fromMsgNum)||(toMsgNum<=fromMsgNum)) return null;    
    var props = new Properties();
    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class",
              "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");               
    var auth = new javax.mail.Authenticator() {                  
      override protected def getPasswordAuthentication(): PasswordAuthentication = {
        new PasswordAuthentication(username,password);
      }
    }
    var session = Session.getDefaultInstance(props,auth);
    var store : Store = session.getStore("pop3s");
    store.connect("smtp.gmail.com", emailAddress, password);
    var inbox : Folder = store.getFolder("Inbox");
    inbox.open(Folder.READ_ONLY);
    var numOfMsgs : Int = inbox.getMessageCount();   
    var batchResult : ArrayBuffer[mailList] = new ArrayBuffer[mailList];
    var msgLimit = toMsgNum;
    
    /*Follow inbox limits*/
    msgLimit = math.min(toMsgNum, numOfMsgs);

    /*Batching the mails*/
    for(i <- Range(fromMsgNum, msgLimit))  {
      var result : String = ""
      var currSubject : String = ""
      var currFrom : String = ""
      var m : Message = inbox.getMessage(i);      
      var o = m.getContent();     
      if (o.isInstanceOf[String]) {
        result += o;
      } 
      else if (o.isInstanceOf[Multipart]) { 
        var mp : Multipart = o.asInstanceOf[Multipart];
        var count :Int = mp.getCount();
       
        for(j <- 0 until count) {           
          var b : BodyPart = mp.getBodyPart(j);
          b.writeTo(System.out);         
          mp.removeBodyPart(b);
          mp.addBodyPart(b);          
        }
      } 
      else if (o.isInstanceOf[InputStream]) {
        var is : InputStream= o.asInstanceOf[InputStream];
        var c : Int = is.read();
        while (c != -1) {
          result+=c;
          c = is.read()
        }
      }                
      var senders : String = "" ;
      for (reciepent <- m.getFrom) {             
        senders += (reciepent + ",")
      } 
      var reciepents : String = "" ;
      for (rs <- m.getAllRecipients) {             
        reciepents += (rs + ",")
      } 
      var curr : mailList = new mailList(m.getSubject,result,senders, reciepents)
      batchResult += curr
    }
    
    var closeChk : Boolean = true;
    inbox.close(closeChk);        
    store.close(); 
    return batchResult;
   }
  
  def emailContent (n: Int): String = {
    if(0>=n) return "";
    var props = new Properties();
    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class",
              "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");               
    var auth = new javax.mail.Authenticator() {                  
      override protected def getPasswordAuthentication(): PasswordAuthentication = {
        return new PasswordAuthentication(username,password);
      }
    }
    var session = Session.getDefaultInstance(props,auth);
    var store : Store = session.getStore("pop3s");
    store.connect("smtp.gmail.com", emailAddress, password);
    var inbox : Folder = store.getFolder("Inbox");
    // open the INBOX folder
    inbox.open(Folder.READ_ONLY);
    var numOfMsgs : Int = inbox.getMessageCount();   
    var result : String = ""
    if(n<=numOfMsgs) {
      var m : Message = inbox.getMessage(n);      
      var o = m.getContent();
      //  Get a message's content:
      //   The type of the returned object depends on the type of the actual content.
      //       A "text/plain" content usually returns a String object.
      //       A "multipart/%lt;whatever here>" object always returns a Multipart object or its subclass.
      //      For unknown content types, any mail-specific encodings are decoded and an InputStream object is returned.       
      if (o.isInstanceOf[String]) {
        result += o;
      } 
      //TODO deal with attachments
      else if (o.isInstanceOf[Multipart]) {
        System.out.println("This is a Multipart");
        var mp : Multipart = o.asInstanceOf[Multipart];
        var count :Int = mp.getCount();
        System.out.println("counted " + count);
        for(i <- 0 until count) {            
          var b : BodyPart = mp.getBodyPart(i);
          b.writeTo(System.out);         
          mp.removeBodyPart(b);
          mp.addBodyPart(b);
          //TODO add to result, currently we just print it!!
        }
      } else if (o.isInstanceOf[InputStream]) {
        var is : InputStream= o.asInstanceOf[InputStream];
        var c : Int = is.read();
        while (c != -1) {
          result+=c;
          c = is.read()
        }
      }    
    }    
    var closeChk : Boolean = true;
    inbox.close(closeChk);        
    store.close();
    return result;
  }

  /** Int n : cannot be 0
   *  let K be number of emails, so 1<=n<=K
   *  
   *  If there are a number of senders, will return:
   *  <sender_email1>,<sender_email2>,<sender_email3>...
   */  
  def emailSender (n: Int): String = {
    if(0>=n) return "";
    var props = new Properties();
    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class",
              "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");               
    var auth = new javax.mail.Authenticator() {                  
      override protected def getPasswordAuthentication(): PasswordAuthentication = {
        return new PasswordAuthentication(username,password);
      }
    }
    var session = Session.getDefaultInstance(props,auth);
    var store : Store = session.getStore("pop3s");
    store.connect("smtp.gmail.com", emailAddress, password);
    var inbox : Folder = store.getFolder("Inbox");
    inbox.open(Folder.READ_ONLY);
    var numOfMsgs : Int = inbox.getMessageCount();   
    var result : String = ""
    if(n<=numOfMsgs) {
      var m : Message = inbox.getMessage(n);
      for (reciepent <- m.getFrom) {             
        result += (reciepent + ",")
      }           
    }    
    var closeChk : Boolean = true;
    inbox.close(closeChk);        
    store.close(); // Close the Store
    return result;
  }
  
  /** Int n : cannot be 0
   *  let K be number of emails, so 1<=n<=K
   */
  def emailSubject (n: Int): String  = {
    if(0>=n) return "";
    var props = new Properties();
    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class",
              "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");               
    var auth = new javax.mail.Authenticator() {                  
      override protected def getPasswordAuthentication(): PasswordAuthentication = {
        return new PasswordAuthentication(username,password);
      }
    }
    var session = Session.getDefaultInstance(props,auth);
    var store : Store = session.getStore("pop3s");
    store.connect("smtp.gmail.com", emailAddress, password);
    var inbox : Folder = store.getFolder("Inbox");
    inbox.open(Folder.READ_ONLY);
    var numOfMsgs : Int = inbox.getMessageCount();   
    var result : String = ""
    if(n<=numOfMsgs) {
      var m : Message = inbox.getMessage(n);
      result += m.getSubject
    }    
    var closeChk : Boolean = true;
    inbox.close(closeChk);        
    store.close(); // Close the Store
    return result;
  }
  
  def receive (): Int = {
    var props = new Properties();
    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class",
              "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");               
    var auth = new javax.mail.Authenticator() {                  
      override protected def getPasswordAuthentication(): PasswordAuthentication = {
        return new PasswordAuthentication(username,password);
      }
    }
    var session = Session.getDefaultInstance(props,auth);
    var store : Store = session.getStore("pop3s");
    //Uses session properties
    //store.connect();
    //uses default port, hostString is like "mail.yourisp.com"
    store.connect("smtp.gmail.com", emailAddress, password);
    //uses specific port, -1 means default
    //store.connect(hostString, portNumberInteger username, password);
    // List folders in the store and list/view messages in a folder:
    // get the INBOX folder  (All stores usually have this one)
    var inbox : Folder = store.getFolder("Inbox");
    inbox.open(Folder.READ_ONLY);
    var numOfMsgs : Int = inbox.getMessageCount();        
    var closeChk : Boolean = true;
    inbox.close(closeChk);
    store.close(); // Close the Store
    return numOfMsgs;
  }
  
  /*  presumed that: "to" is of the format: <email1>,<email2>,<email3>..
   *  with no whitespaces or other illegal characters!
   */
  def sendEmail (to: String, subject: String, content: String): Boolean = {
    var props = new Properties();
    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class",
              "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");               
    var auth = new javax.mail.Authenticator() {                  
      override protected def getPasswordAuthentication(): PasswordAuthentication = {
        return new PasswordAuthentication(username,password);
      }
    }
    var session = Session.getDefaultInstance(props,auth);
 
    try {      
      var reciepents = to.split(",")  /*input string is split by ',' */      
//      for (reciepent <- reciepents) {
//        println(reciepent)
//      }
      val message = new MimeMessage(session)
      // Set the from, to, subject, body text
      message.setFrom(new InternetAddress(emailAddress))
      message.setSubject(subject);
      message.setText(content);
      for (reciepent <- reciepents) {  
        message.setRecipients(Message.RecipientType.TO, reciepent)
        Transport.send(message);
      }
//      System.out.println("Done");
      return true;
    } 
    catch  {
      case mep : MessagingException => {throw new RuntimeException(mep);}
      case e: Exception => {e.printStackTrace} //general excetption is unexpected
        return false;
    }            
    return false;
  }
  
}

/** used for batch email fetching
 * 
 */

class mailList(subject : String, content : String , from : String, allRecipients : String ) {
  private var mailSubject : String = subject;
  private var mailContents : String = content;
  private var mailFrom : String = from;
   private var mailAllRecipients : String = allRecipients;
  
  def getSubject() : String = {
    return mailSubject;
  }
  
  def getContent() : String =  {
    return mailContents;
  }

  def getFrom() : String =  {
    return mailFrom;
  }  
  
  def getAllRecipients : String = {
    return mailAllRecipients;
  }
}